package main

import (
	"errors"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/alecthomas/chroma/v2/quick"
	"github.com/gdamore/tcell/v2"
)

const gSixelBegin = "\033P"

type sixelScreen struct {
	lastFile   string
	lastWin    win
	forceClear bool
}

func (sxs *sixelScreen) clearSixel(win *win, screen tcell.Screen, filePath string) {
	if sxs.lastFile != "" && (filePath != sxs.lastFile || *win != sxs.lastWin || sxs.forceClear) {
		screen.LockRegion(sxs.lastWin.x, sxs.lastWin.y, sxs.lastWin.w, sxs.lastWin.h, false)
	}
}

func (sxs *sixelScreen) printSixel(win *win, screen tcell.Screen, reg *reg) {
	if reg.path == sxs.lastFile && *win == sxs.lastWin && !sxs.forceClear {
		return
	}

	if reg.sixel == nil {
		sxs.lastFile = ""
		return
	}

	cw, ch, err := cellSize(screen)
	if err != nil {
		log.Printf("sixel: %s", err)
		return
	}

	matches := reSixelSize.FindStringSubmatch(*reg.sixel)
	if matches == nil {
		log.Printf("sixel: failed to get image size")
		return
	}
	iw, _ := strconv.Atoi(matches[1])
	ih, _ := strconv.Atoi(matches[2])

	screen.LockRegion(win.x, win.y, (iw+cw-1)/cw, (ih+ch-1)/ch, true)
	writeMessageToLogFile("start output highlighting code")

	var fileContent = *reg.sixel
	var fileSuffixArr = strings.Split(reg.path, ".")
	var suffix = fileSuffixArr[len(fileSuffixArr)-1]

	*reg.sixel = highlightCode(fileContent, suffix)
	//fmt.Fprint(os.Stderr, "\0337")                          // Save cursor position
	//fmt.Fprintf(os.Stderr, "\033[%d;%dH", win.y+1, win.x+1) // Move cursor to position
	//fmt.Fprint(os.Stderr, *reg.sixel)                       // Print sixel
	//fmt.Fprint(os.Stderr, "\0338")                          // Restore cursor position

	sxs.lastFile = reg.path
	sxs.lastWin = *win
	sxs.forceClear = false
}

func highlightCode(code string, suffix string) string {
	switch suffix {
	case "go":
		{

			err := quick.Highlight(os.Stdout, code, "go", "html", "monokai")
			if err != nil {
				log.Printf("sixel: %s", err)
				return code
			}
		}
	case "py":
		{

			err := quick.Highlight(os.Stdout, code, "python", "html", "monokai")
			if err != nil {
				log.Printf("sixel: %s", err)
				return code
			}

		}
	case "js":
		{

			err := quick.Highlight(os.Stdout, code, "javascript", "html", "monokai")
			if err != nil {
				log.Printf("sixel: %s", err)
				return code
			}

		}
	case "html":
		{

			err := quick.Highlight(os.Stdout, code, "html", "html", "monokai")
			if err != nil {
				log.Printf("sixel: %s", err)
				return code
			}

		}
	default:
		return code
	}
	return code
}

func cellSize(screen tcell.Screen) (int, int, error) {
	tty, ok := screen.Tty()
	if !ok {
		// fallback for Windows Terminal
		return 10, 20, nil
	}

	ws, err := tty.WindowSize()
	if err != nil {
		return -1, -1, fmt.Errorf("failed to get window size: %s", err)
	}

	cw, ch := ws.CellDimensions()
	if cw <= 0 || ch <= 0 {
		return -1, -1, errors.New("cell dimensions should be greater than 0")
	}

	return cw, ch, nil
}
